#ifndef MPHTTPCONNECTIONMANAGE_H
#define MPHTTPCONNECTIONMANAGE_H

/******************************
 *
 * 名   称：   Http连接管理器
 * 用   途：   定义HTTP连接管理器相关属性 [ 管理器中缓存的连接个数、管理器中在用的连接个数 ] 与行为方法,具体包括：
 *            1-> 获取Http连接，优先从POOL缓存池中获取，如没有则自动创建
 *            2-> 缓存HTTP连接且缓存具有有效期[受max_cache_seconds约束，默认20秒]
 *            3-> 限制Http连接管理器中活动的Http连接数量，超过上限时将无法在获取HTTP连接[受max_count_allocations约束，默认10个]
 *            4-> 限制Http连接管理器同一域名缓存的Http连接数量，超过上限时将会自动移除缓存中最早的一个连接[受max_count_preKey约束，默认3个]
 *            5-> 限制Http连接管理器中缓存的Http连接数量，超过上限时将尝试开始清理缓存中超时或已关闭的连接，如仍不足则放弃缓存[受_max_count_inpool约束，默认10个]
 *
 * 作用范围：   公共的
 * 创建时间：   2022-10-03
 * 备   注：   1. 由于HttpConnection::ptr_s中持有HttpConnectionManage的智能指针，因此HttpConnectionManage不再使用时，请手动调用clearAndDeactivate()方法先将HttpConnection::ptr_s释放，
 *            2. HttpConnectionManage必须通过createHttpConnectionManage函数创建智能指针对象使用，不要自行实例化
 * 参考：
 * https://sauron7i.blog.csdn.net/article/details/125358585                     [如何实现连接池]
 * https://zhuanlan.zhihu.com/p/95152188                                        [如何实现连接池]
 * https://blog.csdn.net/qq_41172631/article/details/104931674                  [asio模型(io_context 和 thread的使用)]
 * https://blog.csdn.net/qq_41172631/article/details/104933290
 * https://blog.csdn.net/qq_39322743/article/details/79575232                   [理解HTTP请求]
 * https://wenku.baidu.com/view/df9ccc04a6e9856a561252d380eb6294dd882296.html   [资源释放]
 *
 ******************************/

#include <unordered_map>
#include <queue>
//#include <stack>
#include <mutex>
//#include <chrono>
//#include <functional>

#include "mpHttpDefines.h"
#include "mpUrl.h"
#include "mpHttpConnection.h"

using std::chrono::system_clock;

namespace MP{
namespace HTTP{

//需考虑最大连接数的控制,需考虑自动清理???
class HttpConnectionManage : public std::enable_shared_from_this<HttpConnectionManage>
{
public:
    using ptr_s = std::shared_ptr<HttpConnectionManage>;

    HttpConnectionManage(boost::asio::io_context& context);
    virtual ~HttpConnectionManage();

public:
    //获取一个HttpConnection
    HttpConnection::ptr_s getHttpConnection(const std::string& schema,
                                            const std::string& host,
                                            const std::string& port,
                                            const SslSettings& sslSettings);
    //回收HttpConnection
    void recoveryHttpConnection(HttpConnection::ptr_s httpConnection);

    //关闭所有正在执行的HttpConnection
    void closeIsRunning();

    //清空所有HttpConnection然后停止工作
    void clearAndDeactivate();

    std::size_t getConnectionInPoolCount();
    //理论上InUseCount可能会大于max_count_allocations，因为从缓存中转入使用时未进行max_count_allocations的检测
    std::size_t getConnectionInUseCount();

protected:
    //创建一个新的HttpConnection
    virtual HttpConnection::ptr_s createNew(const std::string& schema,
                                            const std::string& host,
                                            const SslSettings& sslSettings);
    //释放HttpConnection
    virtual void releaseHttpConnection(HttpConnection* httpConnection);

    //清理过期或者已关闭的Http连接(缓存的)
    virtual void cleanHttpPoolConnections();
    //计算KEY
    virtual void calculationHttpConnectionKey(const std::string& schema,
                                              const std::string& host,
                                              const std::string& port,
                                              std::string & key);

private:
    boost::asio::io_context& _io_context;
    std::unordered_map<std::string, std::queue<HttpConnection::ptr_s>> _connection_pool;
    std::unordered_map<std::string, std::weak_ptr<HttpConnection>> _in_use_connections;

    std::size_t _max_count_allocations = 10;                                        //允许活动的HttpConnection最大数量
    std::size_t _max_count_inpool = 10;                                             //poll中允许缓存的最大HTTP连接数量
    std::size_t _max_count_preKey = 3;                                              //poll中每个KEY允许缓存的最大HTTP连接数量

    std::size_t _count_inpool = 0;                                                  //缓存中连接数量

    double _max_cache_seconds = 20;                                                 //pool中Http连接缓存有效时间（秒）
    double _min_interval_clean = 60;                                                //清理过期或者已关闭的Http连接的时间的最小间隔（秒）
    std::time_t _last_clean_time = std::time(NULL);                                 //最近一次清理过期或者已关闭的Http连接的时间

    mutable std::mutex _mutex_in_use_connections;
    mutable std::mutex _mutex_connection_pool;
    bool _is_deactivate = false;                                                    //是否已停止工作
};

HttpConnectionManage::ptr_s createHttpConnectionManage(boost::asio::io_context& io_context);

}   //HTTP
}   //MP

#endif // MPHTTPCONNECTIONMANAGE_H
